/*
 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "tlsf.h"

/* Used to cut non-essential functions. */
#define OS_MEM_FREE_BY_TASKID 0

/* the dump size of current broken node when memcheck error */
#define OS_MEM_NODE_DUMP_SIZE 64
/* column num of the output info of mem node */
#define OS_MEM_COLUMN_NUM 8

/* The following is the macro definition and interface implementation related to the TLSF. */

/* Supposing a Second Level Index: SLI = 3. */
#define OS_MEM_SLI 3
/* Giving 1 free list for each small bucket: 4, 8, 12, up to 124. */
#define OS_MEM_SMALL_BUCKET_COUNT 31
#define OS_MEM_SMALL_BUCKET_MAX_SIZE 128
/* Giving OS_MEM_FREE_LIST_NUM free lists for each large bucket. */
#define OS_MEM_LARGE_BUCKET_COUNT 24
#define OS_MEM_FREE_LIST_NUM (1 << OS_MEM_SLI)
/* OS_MEM_SMALL_BUCKET_MAX_SIZE to the power of 2 is 7. */
#define OS_MEM_LARGE_START_BUCKET 7

/* The count of free list. */
#define OS_MEM_FREE_LIST_COUNT (OS_MEM_SMALL_BUCKET_COUNT + (OS_MEM_LARGE_BUCKET_COUNT << OS_MEM_SLI))
/* The bitmap is used to indicate whether the free list is empty, 1: not empty, 0: empty. */
#define OS_MEM_BITMAP_WORDS ((OS_MEM_FREE_LIST_COUNT >> 5) + 1)

#define OS_MEM_BITMAP_MASK 0x1FU

/* Used to find the first bit of 1 in bitmap. */
static inline uint16_t OsMemFFS(uint32_t bitmap)
{
    bitmap &= ~bitmap + 1;
    return (OS_MEM_BITMAP_MASK - CLZ(bitmap));
}

/* Used to find the last bit of 1 in bitmap. */
static inline uint16_t OsMemFLS(uint32_t bitmap)
{
    return (OS_MEM_BITMAP_MASK - CLZ(bitmap));
}

static inline uint32_t OsMemLog2(uint32_t size)
{
    return OsMemFLS(size);
}

/* Get the first level: f = log2(size). */
static inline uint32_t OsMemFlGet(uint32_t size)
{
    if (size < OS_MEM_SMALL_BUCKET_MAX_SIZE)
    {
        return ((size >> 2) - 1); /* 2: The small bucket setup is 4. */
    }
    return OsMemLog2(size);
}

/* Get the second level: s = (size - 2^f) * 2^SLI / 2^f. */
static inline uint32_t OsMemSlGet(uint32_t size, uint32_t fl)
{
    return (((size << OS_MEM_SLI) >> fl) - OS_MEM_FREE_LIST_NUM);
}

static inline uintptr_t LOS_Align(uintptr_t addr, uint32_t boundary)
{
    if ((addr + boundary - 1) > addr) {
        return (addr + boundary - 1) & ~((uintptr_t)(boundary - 1));
    } else {
        return addr & ~((uintptr_t)(boundary - 1));
    }
}

/* The following is the memory algorithm related macro definition and interface implementation. */

struct OsMemNodeHead
{
    uint32_t magic;
    union
    {
        struct OsMemNodeHead *prev; /* The prev is used for current node points to the previous node */
        struct OsMemNodeHead *next; /* The next is used for last node points to the expand node */
    } ptr;
#ifdef LOSCFG_MEM_LEAKCHECK
    uintptr_t linkReg[LOS_RECORD_LR_CNT];
#endif
    uint32_t sizeAndFlag;
};

struct OsMemUsedNodeHead
{
    struct OsMemNodeHead header;
};

struct OsMemFreeNodeHead
{
    struct OsMemNodeHead header;
    struct OsMemFreeNodeHead *prev;
    struct OsMemFreeNodeHead *next;
};

struct OsMemPoolInfo
{
    void *pool;
    uint32_t totalSize;
    uint32_t attr;
#ifdef LOSCFG_MEM_WATERLINE
    uint32_t waterLine;   /* Maximum usage size in a memory pool */
    uint32_t curUsedSize; /* Current usage size in a memory pool */
#endif
};

struct OsMemPoolHead
{
    struct OsMemPoolInfo info;
    uint32_t freeListBitmap[OS_MEM_BITMAP_WORDS];
    struct OsMemFreeNodeHead *freeList[OS_MEM_FREE_LIST_COUNT];
    SPIN_LOCK_S spinlock;
};

/* The memory pool support expand. */
#define OS_MEM_POOL_EXPAND_ENABLE 0x01
/* The memory pool support no lock. */
#define OS_MEM_POOL_LOCK_ENABLE 0x02

#define OS_MEM_NODE_MAGIC 0xABCDDCBA
#define OS_MEM_MIN_ALLOC_SIZE (sizeof(struct OsMemFreeNodeHead) - sizeof(struct OsMemUsedNodeHead))

#define OS_MEM_NODE_USED_FLAG 0x80000000U
#define OS_MEM_NODE_ALIGNED_FLAG 0x40000000U
#define OS_MEM_NODE_LAST_FLAG 0x20000000U /* Sentinel Node */
#define OS_MEM_NODE_ALIGNED_AND_USED_FLAG (OS_MEM_NODE_USED_FLAG | OS_MEM_NODE_ALIGNED_FLAG | OS_MEM_NODE_LAST_FLAG)

#define OS_MEM_NODE_GET_ALIGNED_FLAG(sizeAndFlag) \
    ((sizeAndFlag) & OS_MEM_NODE_ALIGNED_FLAG)
#define OS_MEM_NODE_SET_ALIGNED_FLAG(sizeAndFlag) \
    ((sizeAndFlag) = ((sizeAndFlag) | OS_MEM_NODE_ALIGNED_FLAG))
#define OS_MEM_NODE_GET_ALIGNED_GAPSIZE(sizeAndFlag) \
    ((sizeAndFlag) & ~OS_MEM_NODE_ALIGNED_FLAG)
#define OS_MEM_NODE_GET_USED_FLAG(sizeAndFlag) \
    ((sizeAndFlag) & OS_MEM_NODE_USED_FLAG)
#define OS_MEM_NODE_SET_USED_FLAG(sizeAndFlag) \
    ((sizeAndFlag) = ((sizeAndFlag) | OS_MEM_NODE_USED_FLAG))
#define OS_MEM_NODE_GET_SIZE(sizeAndFlag) \
    ((sizeAndFlag) & ~OS_MEM_NODE_ALIGNED_AND_USED_FLAG)
#define OS_MEM_NODE_SET_LAST_FLAG(sizeAndFlag) \
    ((sizeAndFlag) = ((sizeAndFlag) | OS_MEM_NODE_LAST_FLAG))
#define OS_MEM_NODE_GET_LAST_FLAG(sizeAndFlag) \
    ((sizeAndFlag) & OS_MEM_NODE_LAST_FLAG)

#define OS_MEM_ALIGN_SIZE sizeof(uintptr_t)
#define OS_MEM_IS_POW_TWO(value) ((((uintptr_t)(value)) & ((uintptr_t)(value) - 1)) == 0)
#define OS_MEM_ALIGN(p, alignSize) (((uintptr_t)(p) + (alignSize) - 1) & ~((uintptr_t)((alignSize) - 1)))
#define OS_MEM_IS_ALIGNED(a, b) (!(((uintptr_t)(a)) & (((uintptr_t)(b)) - 1)))
#define OS_MEM_NODE_HEAD_SIZE sizeof(struct OsMemUsedNodeHead)
#define OS_MEM_MIN_POOL_SIZE (OS_MEM_NODE_HEAD_SIZE + sizeof(struct OsMemPoolHead))
#define OS_MEM_NEXT_NODE(node) \
    ((struct OsMemNodeHead *)(void *)((uint8_t *)(node) + OS_MEM_NODE_GET_SIZE((node)->sizeAndFlag)))
#define OS_MEM_FIRST_NODE(pool) \
    (struct OsMemNodeHead *)((uint8_t *)(pool) + sizeof(struct OsMemPoolHead))
#define OS_MEM_END_NODE(pool, size) \
    (struct OsMemNodeHead *)((uint8_t *)(pool) + (size) - OS_MEM_NODE_HEAD_SIZE)
#define OS_MEM_MIDDLE_ADDR_OPEN_END(startAddr, middleAddr, endAddr) \
    (((uint8_t *)(startAddr) <= (uint8_t *)(middleAddr)) && ((uint8_t *)(middleAddr) < (uint8_t *)(endAddr)))
#define OS_MEM_MIDDLE_ADDR(startAddr, middleAddr, endAddr) \
    (((uint8_t *)(startAddr) <= (uint8_t *)(middleAddr)) && ((uint8_t *)(middleAddr) <= (uint8_t *)(endAddr)))
#define OS_MEM_SET_MAGIC(node) ((node)->magic = OS_MEM_NODE_MAGIC)
#define OS_MEM_MAGIC_VALID(node) ((node)->magic == OS_MEM_NODE_MAGIC)

static inline void OsMemFreeNodeAdd(void *pool, struct OsMemFreeNodeHead *node);
static inline uint32_t OsMemFree(struct OsMemPoolHead *pool, struct OsMemNodeHead *node);
static void OsMemInfoPrint(void *pool);
#ifdef LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK
static inline uint32_t OsMemAllocCheck(struct OsMemPoolHead *pool, uint32_t intSave);
#endif

#ifdef LOSCFG_MEM_WATERLINE
static inline void OsMemWaterUsedRecord(struct OsMemPoolHead *pool, uint32_t size)
{
    pool->info.curUsedSize += size;
    if (pool->info.curUsedSize > pool->info.waterLine)
    {
        pool->info.waterLine = pool->info.curUsedSize;
    }
}
#else
static inline void OsMemWaterUsedRecord(struct OsMemPoolHead *pool, uint32_t size)
{
    (void)pool;
    (void)size;
}
#endif

#ifdef LOSCFG_MEM_LEAKCHECK
static inline void OsMemLinkRegisterRecord(struct OsMemNodeHead *node)
{
    LOS_RecordLR(node->linkReg, LOS_RECORD_LR_CNT, LOS_RECORD_LR_CNT, LOS_OMIT_LR_CNT);
}

static inline void OsMemUsedNodePrint(struct OsMemNodeHead *node)
{
    uint32_t count;

    if (OS_MEM_NODE_GET_USED_FLAG(node->sizeAndFlag))
    {
#ifdef __LP64__
        PRINTK("0x%018x: ", node);
#else
        PRINTK("0x%010x: ", node);
#endif
        for (count = 0; count < LOS_RECORD_LR_CNT; count++)
        {
#ifdef __LP64__
            PRINTK(" 0x%018x ", node->linkReg[count]);
#else
            PRINTK(" 0x%010x ", node->linkReg[count]);
#endif
        }
        PRINTK("\n");
    }
}

void OsMemUsedNodeShow(void *pool)
{
    if (pool == NULL)
    {
        PRINTK("input param is NULL\n");
        return;
    }
    if (LOS_MemIntegrityCheck(pool))
    {
        PRINTK("LOS_MemIntegrityCheck error\n");
        return;
    }
    struct OsMemPoolHead *poolInfo = (struct OsMemPoolHead *)pool;
    struct OsMemNodeHead *tmpNode = NULL;
    struct OsMemNodeHead *endNode = NULL;
    uint32_t size;
    uint32_t intSave;
    uint32_t count;

#ifdef __LP64__
    PRINTK("\n\rnode                ");
#else
    PRINTK("\n\rnode        ");
#endif
    for (count = 0; count < LOS_RECORD_LR_CNT; count++)
    {
#ifdef __LP64__
        PRINTK("        LR[%u]       ", count);
#else
        PRINTK("    LR[%u]   ", count);
#endif
    }
    PRINTK("\n");

    MEM_LOCK(poolInfo, intSave);
    endNode = OS_MEM_END_NODE(pool, poolInfo->info.totalSize);

    for (tmpNode = OS_MEM_FIRST_NODE(pool); tmpNode < endNode;
         tmpNode = OS_MEM_NEXT_NODE(tmpNode))
    {
        OsMemUsedNodePrint(tmpNode);
    }

    MEM_UNLOCK(poolInfo, intSave);
}

static void OsMemNodeBacktraceInfo(const struct OsMemNodeHead *tmpNode,
                                   const struct OsMemNodeHead *preNode)
{
    int i;
    PRINTK("\n broken node head LR info: \n");
    for (i = 0; i < LOS_RECORD_LR_CNT; i++)
    {
        PRINTK(" LR[%d]:%#x\n", i, tmpNode->linkReg[i]);
    }

    PRINTK("\n pre node head LR info: \n");
    for (i = 0; i < LOS_RECORD_LR_CNT; i++)
    {
        PRINTK(" LR[%d]:%#x\n", i, preNode->linkReg[i]);
    }
}
#endif

static inline uint32_t OsMemFreeListIndexGet(uint32_t size)
{
    uint32_t fl = OsMemFlGet(size);
    if (size < OS_MEM_SMALL_BUCKET_MAX_SIZE)
    {
        return fl;
    }

    uint32_t sl = OsMemSlGet(size, fl);
    return (OS_MEM_SMALL_BUCKET_COUNT + ((fl - OS_MEM_LARGE_START_BUCKET) << OS_MEM_SLI) + sl);
}

static inline struct OsMemFreeNodeHead *OsMemFindCurSuitableBlock(struct OsMemPoolHead *poolHead,
                                                                  uint32_t index, uint32_t size)
{
    struct OsMemFreeNodeHead *node = NULL;

    for (node = poolHead->freeList[index]; node != NULL; node = node->next)
    {
        if (node->header.sizeAndFlag >= size)
        {
            return node;
        }
    }

    return NULL;
}

#define BITMAP_INDEX(index) ((index) >> 5)
static inline uint32_t OsMemNotEmptyIndexGet(struct OsMemPoolHead *poolHead, uint32_t index)
{
    uint32_t mask;

    mask = poolHead->freeListBitmap[BITMAP_INDEX(index)];
    mask &= ~((1 << (index & OS_MEM_BITMAP_MASK)) - 1);
    if (mask != 0)
    {
        index = OsMemFFS(mask) + (index & ~OS_MEM_BITMAP_MASK);
        return index;
    }

    return OS_MEM_FREE_LIST_COUNT;
}

static inline struct OsMemFreeNodeHead *OsMemFindNextSuitableBlock(void *pool, uint32_t size, uint32_t *outIndex)
{
    struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool;
    uint32_t fl = OsMemFlGet(size);
    uint32_t sl;
    uint32_t index, tmp;
    uint32_t curIndex = OS_MEM_FREE_LIST_COUNT;
    uint32_t mask;

    do
    {
        if (size < OS_MEM_SMALL_BUCKET_MAX_SIZE)
        {
            index = fl;
        }
        else
        {
            sl = OsMemSlGet(size, fl);
            curIndex = ((fl - OS_MEM_LARGE_START_BUCKET) << OS_MEM_SLI) + sl + OS_MEM_SMALL_BUCKET_COUNT;
            index = curIndex + 1;
        }

        tmp = OsMemNotEmptyIndexGet(poolHead, index);
        if (tmp != OS_MEM_FREE_LIST_COUNT)
        {
            index = tmp;
            goto DONE;
        }

        for (index = LOS_Align(index + 1, 32); index < OS_MEM_FREE_LIST_COUNT; index += 32)
        { /* 32: align size */
            mask = poolHead->freeListBitmap[BITMAP_INDEX(index)];
            if (mask != 0)
            {
                index = OsMemFFS(mask) + index;
                goto DONE;
            }
        }
    } while (0);

    if (curIndex == OS_MEM_FREE_LIST_COUNT)
    {
        return NULL;
    }

    *outIndex = curIndex;
    return OsMemFindCurSuitableBlock(poolHead, curIndex, size);
DONE:
    *outIndex = index;
    return poolHead->freeList[index];
}

static inline void OsMemSetFreeListBit(struct OsMemPoolHead *head, uint32_t index)
{
    head->freeListBitmap[BITMAP_INDEX(index)] |= 1U << (index & 0x1f);
}

static inline void OsMemClearFreeListBit(struct OsMemPoolHead *head, uint32_t index)
{
    head->freeListBitmap[BITMAP_INDEX(index)] &= ~(1U << (index & 0x1f));
}

static inline void OsMemListAdd(struct OsMemPoolHead *pool, uint32_t listIndex, struct OsMemFreeNodeHead *node)
{
    struct OsMemFreeNodeHead *firstNode = pool->freeList[listIndex];
    if (firstNode != NULL)
    {
        firstNode->prev = node;
    }
    node->prev = NULL;
    node->next = firstNode;
    pool->freeList[listIndex] = node;
    OsMemSetFreeListBit(pool, listIndex);
    node->header.magic = OS_MEM_NODE_MAGIC;
}

static inline void OsMemListDelete(struct OsMemPoolHead *pool, uint32_t listIndex, struct OsMemFreeNodeHead *node)
{
    if (node == pool->freeList[listIndex])
    {
        pool->freeList[listIndex] = node->next;
        if (node->next == NULL)
        {
            OsMemClearFreeListBit(pool, listIndex);
        }
        else
        {
            node->next->prev = NULL;
        }
    }
    else
    {
        node->prev->next = node->next;
        if (node->next != NULL)
        {
            node->next->prev = node->prev;
        }
    }
    node->header.magic = OS_MEM_NODE_MAGIC;
}

static inline void OsMemFreeNodeAdd(void *pool, struct OsMemFreeNodeHead *node)
{
    uint32_t index = OsMemFreeListIndexGet(node->header.sizeAndFlag);
    if (index >= OS_MEM_FREE_LIST_COUNT)
    {
        LOS_Panic("The index of free lists is error, index = %u\n", index);
        return;
    }
    OsMemListAdd(pool, index, node);
}

static inline void OsMemFreeNodeDelete(void *pool, struct OsMemFreeNodeHead *node)
{
    uint32_t index = OsMemFreeListIndexGet(node->header.sizeAndFlag);
    if (index >= OS_MEM_FREE_LIST_COUNT)
    {
        LOS_Panic("The index of free lists is error, index = %u\n", index);
        return;
    }
    OsMemListDelete(pool, index, node);
}

static inline struct OsMemNodeHead *OsMemFreeNodeGet(void *pool, uint32_t size)
{
    struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool;
    uint32_t index;
    struct OsMemFreeNodeHead *firstNode = OsMemFindNextSuitableBlock(pool, size, &index);
    if (firstNode == NULL)
    {
        return NULL;
    }

    OsMemListDelete(poolHead, index, firstNode);

    return &firstNode->header;
}

static inline void OsMemMergeNode(struct OsMemNodeHead *node)
{
    struct OsMemNodeHead *nextNode = NULL;

    node->ptr.prev->sizeAndFlag += node->sizeAndFlag;
    nextNode = (struct OsMemNodeHead *)((uintptr_t)node + node->sizeAndFlag);
    if (!OS_MEM_NODE_GET_LAST_FLAG(nextNode->sizeAndFlag))
    {
        nextNode->ptr.prev = node->ptr.prev;
    }
}

static inline void OsMemSplitNode(void *pool, struct OsMemNodeHead *allocNode, uint32_t allocSize)
{
    struct OsMemFreeNodeHead *newFreeNode = NULL;
    struct OsMemNodeHead *nextNode = NULL;

    newFreeNode = (struct OsMemFreeNodeHead *)(void *)((uint8_t *)allocNode + allocSize);
    newFreeNode->header.ptr.prev = allocNode;
    newFreeNode->header.sizeAndFlag = allocNode->sizeAndFlag - allocSize;
    allocNode->sizeAndFlag = allocSize;
    nextNode = OS_MEM_NEXT_NODE(&newFreeNode->header);
    if (!OS_MEM_NODE_GET_LAST_FLAG(nextNode->sizeAndFlag))
    {
        nextNode->ptr.prev = &newFreeNode->header;
        if (!OS_MEM_NODE_GET_USED_FLAG(nextNode->sizeAndFlag))
        {
            OsMemFreeNodeDelete(pool, (struct OsMemFreeNodeHead *)nextNode);
            OsMemMergeNode(nextNode);
        }
    }

    OsMemFreeNodeAdd(pool, newFreeNode);
}

static inline void *OsMemCreateUsedNode(void *addr)
{
    struct OsMemUsedNodeHead *node = (struct OsMemUsedNodeHead *)addr;

    return node + 1;
}

int OsMemPoolInit(void *pool, uint32_t size)
{
    struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool;
    struct OsMemNodeHead *newNode = NULL;
    struct OsMemNodeHead *endNode = NULL;

    (void)memset(poolHead, sizeof(struct OsMemPoolHead), 0, sizeof(struct OsMemPoolHead));

    MEM_LOCK_INIT(&poolHead);
    poolHead->info.pool = pool;
    poolHead->info.totalSize = size;
    poolHead->info.attr = OS_MEM_POOL_LOCK_ENABLE; /* default attr: lock, not expand. */

    newNode = OS_MEM_FIRST_NODE(pool);
    newNode->sizeAndFlag = (size - sizeof(struct OsMemPoolHead) - OS_MEM_NODE_HEAD_SIZE);
    newNode->ptr.prev = NULL;
    newNode->magic = OS_MEM_NODE_MAGIC;
    OsMemFreeNodeAdd(pool, (struct OsMemFreeNodeHead *)newNode);

    /* The last mem node */
    endNode = OS_MEM_END_NODE(pool, size);
    endNode->magic = OS_MEM_NODE_MAGIC;

    endNode->sizeAndFlag = 0;
    endNode->ptr.prev = newNode;
    OS_MEM_NODE_SET_USED_FLAG(endNode->sizeAndFlag);

#ifdef LOSCFG_MEM_WATERLINE
    poolHead->info.curUsedSize = sizeof(struct OsMemPoolHead) + OS_MEM_NODE_HEAD_SIZE;
    poolHead->info.waterLine = poolHead->info.curUsedSize;
#endif

    return 0;
}

static inline void *OsMemAlloc(struct OsMemPoolHead *pool, uint32_t size, uint32_t intSave)
{
    struct OsMemNodeHead *allocNode = NULL;

#ifdef LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK
    if (OsMemAllocCheck(pool, intSave) == -EINVAL)
    {
        return NULL;
    }
#endif

    uint32_t allocSize = OS_MEM_ALIGN(size + OS_MEM_NODE_HEAD_SIZE, OS_MEM_ALIGN_SIZE);

    allocNode = OsMemFreeNodeGet(pool, allocSize);
    if (allocNode == NULL)
    {
        MEM_UNLOCK(pool, intSave);
        PRINT_ERR("---------------------------------------------------"
                  "--------------------------------------------------------\n");
        //OsMemInfoPrint(pool);
        PRINT_ERR("[%s] No suitable free block, require free node size: 0x%x\n", __FUNCTION__, allocSize);
        PRINT_ERR("----------------------------------------------------"
                  "-------------------------------------------------------\n");
        MEM_LOCK(pool, intSave);
        return NULL;
    }

    if ((allocSize + OS_MEM_NODE_HEAD_SIZE + OS_MEM_MIN_ALLOC_SIZE) <= allocNode->sizeAndFlag)
    {
        OsMemSplitNode(pool, allocNode, allocSize);
    }

    OS_MEM_NODE_SET_USED_FLAG(allocNode->sizeAndFlag);
    OsMemWaterUsedRecord(pool, OS_MEM_NODE_GET_SIZE(allocNode->sizeAndFlag));

#ifdef LOSCFG_MEM_LEAKCHECK
    OsMemLinkRegisterRecord(allocNode);
#endif
    return OsMemCreateUsedNode((void *)allocNode);
}

void *LOS_MemAlloc(void *pool, uint32_t size)
{
    if (size < OS_MEM_MIN_ALLOC_SIZE)
    {
        size = OS_MEM_MIN_ALLOC_SIZE;
    }

    struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool;
    void *ptr = NULL;
    uint32_t intSave;

    do
    {
        if (OS_MEM_NODE_GET_USED_FLAG(size) || OS_MEM_NODE_GET_ALIGNED_FLAG(size))
        {
            break;
        }
        MEM_LOCK(poolHead, intSave);
        ptr = OsMemAlloc(poolHead, size, intSave);
        MEM_UNLOCK(poolHead, intSave);
    } while (0);

    return ptr;
}

void *LOS_MemAllocAlign(void *pool, uint32_t size, uint32_t boundary)
{
    uint32_t gapSize;

    if ((pool == NULL) || (size == 0) || (boundary == 0) || !OS_MEM_IS_POW_TWO(boundary) ||
        !OS_MEM_IS_ALIGNED(boundary, sizeof(void *)))
    {
        return NULL;
    }

    if (size < OS_MEM_MIN_ALLOC_SIZE)
    {
        size = OS_MEM_MIN_ALLOC_SIZE;
    }

    /*
     * sizeof(gapSize) bytes stores offset between alignedPtr and ptr,
     * the ptr has been OS_MEM_ALIGN_SIZE(4 or 8) aligned, so maximum
     * offset between alignedPtr and ptr is boundary - OS_MEM_ALIGN_SIZE
     */
    if ((boundary - sizeof(gapSize)) > ((uint32_t)(-1) - size))
    {
        return NULL;
    }

    uint32_t useSize = (size + boundary) - sizeof(gapSize);
    if (OS_MEM_NODE_GET_USED_FLAG(useSize) || OS_MEM_NODE_GET_ALIGNED_FLAG(useSize))
    {
        return NULL;
    }

    struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool;
    uint32_t intSave;
    void *ptr = NULL;
    void *alignedPtr = NULL;

    do
    {
        MEM_LOCK(poolHead, intSave);
        ptr = OsMemAlloc(pool, useSize, intSave);
        MEM_UNLOCK(poolHead, intSave);
        alignedPtr = (void *)OS_MEM_ALIGN(ptr, boundary);
        if (ptr == alignedPtr)
        {
            break;
        }

        /* store gapSize in address (ptr - 4), it will be checked while free */
        gapSize = (uint32_t)((uintptr_t)alignedPtr - (uintptr_t)ptr);
        struct OsMemUsedNodeHead *allocNode = (struct OsMemUsedNodeHead *)ptr - 1;
        OS_MEM_NODE_SET_ALIGNED_FLAG(allocNode->header.sizeAndFlag);
        OS_MEM_NODE_SET_ALIGNED_FLAG(gapSize);
        *(uint32_t *)((uintptr_t)alignedPtr - sizeof(gapSize)) = gapSize;

        ptr = alignedPtr;
    } while (0);

    OsHookCall(LOS_HOOK_TYPE_MEM_ALLOCALIGN, pool, ptr, size, boundary);
    return ptr;
}

static inline bool OsMemAddrValidCheck(const struct OsMemPoolHead *pool, const void *addr)
{
    uint32_t size;

    /* First node prev is NULL */
    if (addr == NULL)
    {
        return true;
    }

    size = pool->info.totalSize;
    if (OS_MEM_MIDDLE_ADDR_OPEN_END(pool + 1, addr, (uintptr_t)pool + size))
    {
        return true;
    }

    return false;
}

static inline bool OsMemIsNodeValid(const struct OsMemNodeHead *node, const struct OsMemNodeHead *startNode,
                                    const struct OsMemNodeHead *endNode,
                                    const struct OsMemPoolHead *poolInfo)
{
    if (!OS_MEM_MIDDLE_ADDR(startNode, node, endNode))
    {
        return false;
    }

    if (OS_MEM_NODE_GET_USED_FLAG(node->sizeAndFlag))
    {
        if (!OS_MEM_MAGIC_VALID(node))
        {
            return false;
        }
        return true;
    }

    if (!OsMemAddrValidCheck(poolInfo, node->ptr.prev))
    {
        return false;
    }

    return true;
}

static bool MemCheckUsedNode(const struct OsMemPoolHead *pool, const struct OsMemNodeHead *node,
                             const struct OsMemNodeHead *startNode, const struct OsMemNodeHead *endNode)
{
    if (!OsMemIsNodeValid(node, startNode, endNode, pool))
    {
        return false;
    }

    if (!OS_MEM_NODE_GET_USED_FLAG(node->sizeAndFlag))
    {
        return false;
    }

    const struct OsMemNodeHead *nextNode = OS_MEM_NEXT_NODE(node);
    if (!OsMemIsNodeValid(nextNode, startNode, endNode, pool))
    {
        return false;
    }

    if (!OS_MEM_NODE_GET_LAST_FLAG(nextNode->sizeAndFlag))
    {
        if (nextNode->ptr.prev != node)
        {
            return false;
        }
    }

    if ((node != startNode) &&
        ((!OsMemIsNodeValid(node->ptr.prev, startNode, endNode, pool)) ||
         (OS_MEM_NEXT_NODE(node->ptr.prev) != node)))
    {
        return false;
    }

    return true;
}

static uint32_t OsMemCheckUsedNode(const struct OsMemPoolHead *pool, const struct OsMemNodeHead *node)
{
    struct OsMemNodeHead *startNode = (struct OsMemNodeHead *)OS_MEM_FIRST_NODE(pool);
    struct OsMemNodeHead *endNode = (struct OsMemNodeHead *)OS_MEM_END_NODE(pool, pool->info.totalSize);
    bool doneFlag = false;

    do
    {
        doneFlag = MemCheckUsedNode(pool, node, startNode, endNode);
        if (!doneFlag)
        {
            return -EINVAL;
        }
    } while (!doneFlag);

    return 0;
}

static inline uint32_t OsMemFree(struct OsMemPoolHead *pool, struct OsMemNodeHead *node)
{
    uint32_t ret = OsMemCheckUsedNode(pool, node);
    if (ret != 0)
    {
        PRINT_ERR("OsMemFree check error!\n");
        return ret;
    }

#ifdef LOSCFG_MEM_WATERLINE
    pool->info.curUsedSize -= OS_MEM_NODE_GET_SIZE(node->sizeAndFlag);
#endif

    node->sizeAndFlag = OS_MEM_NODE_GET_SIZE(node->sizeAndFlag);
#ifdef LOSCFG_MEM_LEAKCHECK
    OsMemLinkRegisterRecord(node);
#endif

    struct OsMemNodeHead *preNode = node->ptr.prev; /* merage preNode */
    if ((preNode != NULL) && !OS_MEM_NODE_GET_USED_FLAG(preNode->sizeAndFlag))
    {
        OsMemFreeNodeDelete(pool, (struct OsMemFreeNodeHead *)preNode);
        OsMemMergeNode(node);
        node = preNode;
    }

    struct OsMemNodeHead *nextNode = OS_MEM_NEXT_NODE(node); /* merage nextNode */
    if ((nextNode != NULL) && !OS_MEM_NODE_GET_USED_FLAG(nextNode->sizeAndFlag))
    {
        OsMemFreeNodeDelete(pool, (struct OsMemFreeNodeHead *)nextNode);
        OsMemMergeNode(nextNode);
    }

    OsMemFreeNodeAdd(pool, (struct OsMemFreeNodeHead *)node);

    return ret;
}

int LOS_MemFree(void *pool, void *ptr)
{
    uint32_t intSave;
    int ret = -EINVAL;

    if ((pool == NULL) || (ptr == NULL) || !OS_MEM_IS_ALIGNED(pool, sizeof(void *)) ||
        !OS_MEM_IS_ALIGNED(ptr, sizeof(void *)))
    {
        return ret;
    }
    OsHookCall(LOS_HOOK_TYPE_MEM_FREE, pool, ptr);

    struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool;
    struct OsMemNodeHead *node = NULL;

    do
    {
        uint32_t gapSize = *(uint32_t *)((uintptr_t)ptr - sizeof(uint32_t));
        if (OS_MEM_NODE_GET_ALIGNED_FLAG(gapSize) && OS_MEM_NODE_GET_USED_FLAG(gapSize))
        {
            PRINT_ERR("[%s:%d]gapSize:0x%x error\n", __FUNCTION__, __LINE__, gapSize);
            break;
        }

        node = (struct OsMemNodeHead *)((uintptr_t)ptr - OS_MEM_NODE_HEAD_SIZE);

        if (OS_MEM_NODE_GET_ALIGNED_FLAG(gapSize))
        {
            gapSize = OS_MEM_NODE_GET_ALIGNED_GAPSIZE(gapSize);
            if ((gapSize & (OS_MEM_ALIGN_SIZE - 1)) || (gapSize > ((uintptr_t)ptr - OS_MEM_NODE_HEAD_SIZE)))
            {
                PRINT_ERR("illegal gapSize: 0x%x\n", gapSize);
                break;
            }
            node = (struct OsMemNodeHead *)((uintptr_t)ptr - gapSize - OS_MEM_NODE_HEAD_SIZE);
        }
        MEM_LOCK(poolHead, intSave);
        ret = OsMemFree(poolHead, node);
        MEM_UNLOCK(poolHead, intSave);
    } while (0);

    return ret;
}

static inline void OsMemReAllocSmaller(void *pool, uint32_t allocSize, struct OsMemNodeHead *node, uint32_t nodeSize)
{
#ifdef LOSCFG_MEM_WATERLINE
    struct OsMemPoolHead *poolInfo = (struct OsMemPoolHead *)pool;
#endif
    node->sizeAndFlag = nodeSize;
    if ((allocSize + OS_MEM_NODE_HEAD_SIZE + OS_MEM_MIN_ALLOC_SIZE) <= nodeSize)
    {
        OsMemSplitNode(pool, node, allocSize);
        OS_MEM_NODE_SET_USED_FLAG(node->sizeAndFlag);
#ifdef LOSCFG_MEM_WATERLINE
        poolInfo->info.curUsedSize -= nodeSize - allocSize;
#endif
    }
    OS_MEM_NODE_SET_USED_FLAG(node->sizeAndFlag);
#ifdef LOSCFG_MEM_LEAKCHECK
    OsMemLinkRegisterRecord(node);
#endif
}

static inline void OsMemMergeNodeForReAllocBigger(void *pool, uint32_t allocSize, struct OsMemNodeHead *node,
                                                  uint32_t nodeSize, struct OsMemNodeHead *nextNode)
{
    node->sizeAndFlag = nodeSize;
    OsMemFreeNodeDelete(pool, (struct OsMemFreeNodeHead *)nextNode);
    OsMemMergeNode(nextNode);

    if ((allocSize + OS_MEM_NODE_HEAD_SIZE + OS_MEM_MIN_ALLOC_SIZE) <= node->sizeAndFlag)
    {
        OsMemSplitNode(pool, node, allocSize);
    }
    OS_MEM_NODE_SET_USED_FLAG(node->sizeAndFlag);
    OsMemWaterUsedRecord((struct OsMemPoolHead *)pool, node->sizeAndFlag - nodeSize);
#ifdef LOSCFG_MEM_LEAKCHECK
    OsMemLinkRegisterRecord(node);
#endif
}

static inline void *OsGetRealPtr(const void *pool, void *ptr)
{
    void *realPtr = ptr;
    uint32_t gapSize = *((uint32_t *)((uintptr_t)ptr - sizeof(uint32_t)));

    if (OS_MEM_NODE_GET_ALIGNED_FLAG(gapSize) && OS_MEM_NODE_GET_USED_FLAG(gapSize))
    {
        PRINT_ERR("[%s:%d]gapSize:0x%x error\n", __FUNCTION__, __LINE__, gapSize);
        return NULL;
    }
    if (OS_MEM_NODE_GET_ALIGNED_FLAG(gapSize))
    {
        gapSize = OS_MEM_NODE_GET_ALIGNED_GAPSIZE(gapSize);
        if ((gapSize & (OS_MEM_ALIGN_SIZE - 1)) ||
            (gapSize > ((uintptr_t)ptr - OS_MEM_NODE_HEAD_SIZE - (uintptr_t)pool)))
        {
            PRINT_ERR("[%s:%d]gapSize:0x%x error\n", __FUNCTION__, __LINE__, gapSize);
            return NULL;
        }
        realPtr = (void *)((uintptr_t)ptr - (uintptr_t)gapSize);
    }
    return realPtr;
}

static inline void *OsMemRealloc(struct OsMemPoolHead *pool, const void *ptr,
                                 struct OsMemNodeHead *node, uint32_t size, uint32_t intSave)
{
    struct OsMemNodeHead *nextNode = NULL;
    uint32_t allocSize = OS_MEM_ALIGN(size + OS_MEM_NODE_HEAD_SIZE, OS_MEM_ALIGN_SIZE);
    uint32_t nodeSize = OS_MEM_NODE_GET_SIZE(node->sizeAndFlag);
    void *tmpPtr = NULL;

    if (nodeSize >= allocSize)
    {
        OsMemReAllocSmaller(pool, allocSize, node, nodeSize);
        return (void *)ptr;
    }

    nextNode = OS_MEM_NEXT_NODE(node);
    if (!OS_MEM_NODE_GET_USED_FLAG(nextNode->sizeAndFlag) &&
        ((nextNode->sizeAndFlag + nodeSize) >= allocSize))
    {
        OsMemMergeNodeForReAllocBigger(pool, allocSize, node, nodeSize, nextNode);
        return (void *)ptr;
    }

    tmpPtr = OsMemAlloc(pool, size, intSave);
    if (tmpPtr != NULL)
    {
        if (memcpy_s(tmpPtr, size, ptr, (nodeSize - OS_MEM_NODE_HEAD_SIZE)) != 0)
        {
            MEM_UNLOCK(pool, intSave);
            (void)LOS_MemFree((void *)pool, (void *)tmpPtr);
            MEM_LOCK(pool, intSave);
            return NULL;
        }
        (void)OsMemFree(pool, node);
    }
    return tmpPtr;
}

void *LOS_MemRealloc(void *pool, void *ptr, uint32_t size)
{
    if ((pool == NULL) || OS_MEM_NODE_GET_USED_FLAG(size) || OS_MEM_NODE_GET_ALIGNED_FLAG(size))
    {
        return NULL;
    }
    OsHookCall(LOS_HOOK_TYPE_MEM_REALLOC, pool, ptr, size);
    if (size < OS_MEM_MIN_ALLOC_SIZE)
    {
        size = OS_MEM_MIN_ALLOC_SIZE;
    }

    if (ptr == NULL)
    {
        return LOS_MemAlloc(pool, size);
    }

    if (size == 0)
    {
        (void)LOS_MemFree(pool, ptr);
        return NULL;
    }

    struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool;
    struct OsMemNodeHead *node = NULL;
    void *newPtr = NULL;
    uint32_t intSave;

    MEM_LOCK(poolHead, intSave);
    do
    {
        ptr = OsGetRealPtr(pool, ptr);
        if (ptr == NULL)
        {
            break;
        }

        node = (struct OsMemNodeHead *)((uintptr_t)ptr - OS_MEM_NODE_HEAD_SIZE);
        if (OsMemCheckUsedNode(pool, node) != 0)
        {
            break;
        }

        newPtr = OsMemRealloc(pool, ptr, node, size, intSave);
    } while (0);
    MEM_UNLOCK(poolHead, intSave);

    return newPtr;
}

uint32_t LOS_MemPoolSizeGet(const void *pool)
{
    uint32_t count = 0;

    if (pool == NULL)
    {
        return -EINVAL;
    }

    count += ((struct OsMemPoolHead *)pool)->info.totalSize;

    return count;
}

uint32_t LOS_MemTotalUsedGet(void *pool)
{
    struct OsMemNodeHead *tmpNode = NULL;
    struct OsMemPoolHead *poolInfo = (struct OsMemPoolHead *)pool;
    struct OsMemNodeHead *endNode = NULL;
    uint32_t memUsed = 0;
    uint32_t intSave;

    if (pool == NULL)
    {
        return -EINVAL;
    }

    MEM_LOCK(poolInfo, intSave);
    endNode = OS_MEM_END_NODE(pool, poolInfo->info.totalSize);

    for (tmpNode = OS_MEM_FIRST_NODE(pool); tmpNode < endNode;)
    {
        if (OS_MEM_NODE_GET_USED_FLAG(tmpNode->sizeAndFlag))
        {
            memUsed += OS_MEM_NODE_GET_SIZE(tmpNode->sizeAndFlag);
        }
        tmpNode = OS_MEM_NEXT_NODE(tmpNode);
    }

    MEM_UNLOCK(poolInfo, intSave);

    return memUsed;
}

static inline void OsMemMagicCheckPrint(struct OsMemNodeHead **tmpNode)
{
    PRINT_ERR("[%s], %d, memory check error!\n"
              "memory used but magic num wrong, magic num = %#x\n",
              __FUNCTION__, __LINE__, (*tmpNode)->magic);
}

static uint32_t OsMemAddrValidCheckPrint(const void *pool, struct OsMemFreeNodeHead **tmpNode)
{
    if (((*tmpNode)->prev != NULL) && !OsMemAddrValidCheck(pool, (*tmpNode)->prev))
    {
        PRINT_ERR("[%s], %d, memory check error!\n"
                  " freeNode.prev:%#x is out of legal mem range\n",
                  __FUNCTION__, __LINE__, (*tmpNode)->prev);
        return -EINVAL;
    }
    if (((*tmpNode)->next != NULL) && !OsMemAddrValidCheck(pool, (*tmpNode)->next))
    {
        PRINT_ERR("[%s], %d, memory check error!\n"
                  " freeNode.next:%#x is out of legal mem range\n",
                  __FUNCTION__, __LINE__, (*tmpNode)->next);
        return -EINVAL;
    }

    return 0;
}

static int OsMemIntegrityCheckSub(struct OsMemNodeHead **tmpNode, const void *pool,
                                  const struct OsMemNodeHead *endNode)
{
    if (!OS_MEM_MAGIC_VALID(*tmpNode))
    {
        OsMemMagicCheckPrint(tmpNode);
        return -EINVAL;
    }

    if (!OS_MEM_NODE_GET_USED_FLAG((*tmpNode)->sizeAndFlag))
    { /* is free node, check free node range */
        if (OsMemAddrValidCheckPrint(pool, (struct OsMemFreeNodeHead **)tmpNode))
        {
            return -EINVAL;
        }
    }

    return 0;
}

static uint32_t OsMemFreeListNodeCheck(const struct OsMemPoolHead *pool,
                                       const struct OsMemFreeNodeHead *node)
{
    if (!OsMemAddrValidCheck(pool, node) ||
        !OsMemAddrValidCheck(pool, node->prev) ||
        !OsMemAddrValidCheck(pool, node->next) ||
        !OsMemAddrValidCheck(pool, node->header.ptr.prev))
    {
        return -EINVAL;
    }

    if (!OS_MEM_IS_ALIGNED(node, sizeof(void *)) ||
        !OS_MEM_IS_ALIGNED(node->prev, sizeof(void *)) ||
        !OS_MEM_IS_ALIGNED(node->next, sizeof(void *)) ||
        !OS_MEM_IS_ALIGNED(node->header.ptr.prev, sizeof(void *)))
    {
        return -EINVAL;
    }

    return 0;
}

static void OsMemPoolHeadCheck(const struct OsMemPoolHead *pool)
{
    struct OsMemFreeNodeHead *tmpNode = NULL;
    uint32_t index;
    uint32_t flag = 0;

    if ((pool->info.pool != pool) || !OS_MEM_IS_ALIGNED(pool, sizeof(void *)))
    {
        PRINT_ERR("wrong mem pool addr: %#x, func:%s, line:%d\n", pool, __FUNCTION__, __LINE__);
        return;
    }

    for (index = 0; index < OS_MEM_FREE_LIST_COUNT; index++)
    {
        for (tmpNode = pool->freeList[index]; tmpNode != NULL; tmpNode = tmpNode->next)
        {
            if (OsMemFreeListNodeCheck(pool, tmpNode))
            {
                flag = 1;
                PRINT_ERR("FreeListIndex: %u, node: %#x, bNode: %#x, prev: %#x, next: %#x\n",
                          index, tmpNode, tmpNode->header.ptr.prev, tmpNode->prev, tmpNode->next);
                goto OUT;
            }
        }
    }

OUT:
    if (flag)
    {
        PRINTK("mem pool info: poolAddr: %#x, poolSize: 0x%x\n", pool, pool->info.totalSize);
#ifdef LOSCFG_MEM_WATERLINE
        PRINTK("mem pool info: poolWaterLine: 0x%x, poolCurUsedSize: 0x%x\n", pool->info.waterLine,
               pool->info.curUsedSize);
#endif
    }
}

static uint32_t OsMemIntegrityCheck(const struct OsMemPoolHead *pool, struct OsMemNodeHead **tmpNode,
                                    struct OsMemNodeHead **preNode)
{
    struct OsMemNodeHead *endNode = OS_MEM_END_NODE(pool, pool->info.totalSize);

    OsMemPoolHeadCheck(pool);

    *preNode = OS_MEM_FIRST_NODE(pool);
    do
    {
        for (*tmpNode = *preNode; *tmpNode < endNode; *tmpNode = OS_MEM_NEXT_NODE(*tmpNode))
        {
            if (OsMemIntegrityCheckSub(tmpNode, pool, endNode) == -EINVAL)
            {
                return -EINVAL;
            }
            *preNode = *tmpNode;
        }

        {
            break;
        }
    } while (1);
    return 0;
}

static void OsMemNodeInfo(const struct OsMemNodeHead *tmpNode,
                          const struct OsMemNodeHead *preNode)
{
    struct OsMemUsedNodeHead *usedNode = NULL;
    struct OsMemFreeNodeHead *freeNode = NULL;

    if (tmpNode == preNode)
    {
        PRINTK("\n the broken node is the first node\n");
    }

    if (OS_MEM_NODE_GET_USED_FLAG(tmpNode->sizeAndFlag))
    {
        usedNode = (struct OsMemUsedNodeHead *)tmpNode;
        PRINTK("\n broken node head: %#x  %#x  %#x, ",
               usedNode->header.ptr.prev, usedNode->header.magic, usedNode->header.sizeAndFlag);
    }
    else
    {
        freeNode = (struct OsMemFreeNodeHead *)tmpNode;
        PRINTK("\n broken node head: %#x  %#x  %#x  %#x, %#x",
               freeNode->header.ptr.prev, freeNode->next, freeNode->prev, freeNode->header.magic,
               freeNode->header.sizeAndFlag);
    }

    if (OS_MEM_NODE_GET_USED_FLAG(preNode->sizeAndFlag))
    {
        usedNode = (struct OsMemUsedNodeHead *)preNode;
        PRINTK("prev node head: %#x  %#x  %#x\n",
               usedNode->header.ptr.prev, usedNode->header.magic, usedNode->header.sizeAndFlag);
    }
    else
    {
        freeNode = (struct OsMemFreeNodeHead *)preNode;
        PRINTK("prev node head: %#x  %#x  %#x  %#x, %#x",
               freeNode->header.ptr.prev, freeNode->next, freeNode->prev, freeNode->header.magic,
               freeNode->header.sizeAndFlag);
    }

#ifdef LOSCFG_MEM_LEAKCHECK
    OsMemNodeBacktraceInfo(tmpNode, preNode);
#endif

    PRINTK("\n---------------------------------------------\n");
    PRINTK(" dump mem tmpNode:%#x ~ %#x\n", tmpNode, ((uintptr_t)tmpNode + OS_MEM_NODE_DUMP_SIZE));
    OsDumpMemByte(OS_MEM_NODE_DUMP_SIZE, (uintptr_t)tmpNode);
    PRINTK("\n---------------------------------------------\n");
    if (preNode != tmpNode)
    {
        PRINTK(" dump mem :%#x ~ tmpNode:%#x\n", ((uintptr_t)tmpNode - OS_MEM_NODE_DUMP_SIZE), tmpNode);
        OsDumpMemByte(OS_MEM_NODE_DUMP_SIZE, ((uintptr_t)tmpNode - OS_MEM_NODE_DUMP_SIZE));
        PRINTK("\n---------------------------------------------\n");
    }
}

static void OsMemIntegrityCheckError(struct OsMemPoolHead *pool,
                                     const struct OsMemNodeHead *tmpNode,
                                     const struct OsMemNodeHead *preNode,
                                     uint32_t intSave)
{
    OsMemNodeInfo(tmpNode, preNode);

    MEM_UNLOCK(pool, intSave);
    LOS_Panic("Memory integrity check error, cur node: %#x, pre node: %#x\n", tmpNode, preNode);
}

#ifdef LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK
static inline uint32_t OsMemAllocCheck(struct OsMemPoolHead *pool, uint32_t intSave)
{
    struct OsMemNodeHead *tmpNode = NULL;
    struct OsMemNodeHead *preNode = NULL;

    if (OsMemIntegrityCheck(pool, &tmpNode, &preNode))
    {
        OsMemIntegrityCheckError(pool, tmpNode, preNode, intSave);
        return -EINVAL;
    }
    return 0;
}
#endif

uint32_t LOS_MemIntegrityCheck(const void *pool)
{
    if (pool == NULL)
    {
        return -EINVAL;
    }

    struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool;
    struct OsMemNodeHead *tmpNode = NULL;
    struct OsMemNodeHead *preNode = NULL;
    uint32_t intSave = 0;

    MEM_LOCK(poolHead, intSave);
    if (OsMemIntegrityCheck(poolHead, &tmpNode, &preNode))
    {
        goto ERROR_OUT;
    }
    MEM_UNLOCK(poolHead, intSave);
    return 0;

ERROR_OUT:
    OsMemIntegrityCheckError(poolHead, tmpNode, preNode, intSave);
    return -EINVAL;
}

static inline void OsMemInfoGet(struct OsMemPoolHead *poolInfo, struct OsMemNodeHead *node,
                                LOS_MEM_POOL_STATUS *poolStatus)
{
    uint32_t totalUsedSize = 0;
    uint32_t totalFreeSize = 0;
    uint32_t usedNodeNum = 0;
    uint32_t freeNodeNum = 0;
    uint32_t maxFreeSize = 0;
    uint32_t size;

    if (!OS_MEM_NODE_GET_USED_FLAG(node->sizeAndFlag))
    {
        size = OS_MEM_NODE_GET_SIZE(node->sizeAndFlag);
        ++freeNodeNum;
        totalFreeSize += size;
        if (maxFreeSize < size)
        {
            maxFreeSize = size;
        }
    }
    else
    {
        size = OS_MEM_NODE_GET_SIZE(node->sizeAndFlag);
        ++usedNodeNum;
        totalUsedSize += size;
    }

    poolStatus->totalUsedSize += totalUsedSize;
    poolStatus->totalFreeSize += totalFreeSize;
    poolStatus->maxFreeNodeSize = MAX(poolStatus->maxFreeNodeSize, maxFreeSize);
    poolStatus->usedNodeNum += usedNodeNum;
    poolStatus->freeNodeNum += freeNodeNum;
}

uint32_t LOS_MemInfoGet(void *pool, LOS_MEM_POOL_STATUS *poolStatus)
{
    struct OsMemPoolHead *poolInfo = pool;

    if (poolStatus == NULL)
    {
        PRINT_ERR("can't use NULL addr to save info\n");
        return -EINVAL;
    }

    if ((pool == NULL) || (poolInfo->info.pool != pool))
    {
        PRINT_ERR("wrong mem pool addr: %#x, line:%d\n", poolInfo, __LINE__);
        return -EINVAL;
    }

    (void)memset(poolStatus, sizeof(LOS_MEM_POOL_STATUS), 0, sizeof(LOS_MEM_POOL_STATUS));

    struct OsMemNodeHead *tmpNode = NULL;
    struct OsMemNodeHead *endNode = NULL;
    long intSave;

    MEM_LOCK(poolInfo, intSave);
    endNode = OS_MEM_END_NODE(pool, poolInfo->info.totalSize);

    for (tmpNode = OS_MEM_FIRST_NODE(pool); tmpNode < endNode; tmpNode = OS_MEM_NEXT_NODE(tmpNode))
    {
        OsMemInfoGet(poolInfo, tmpNode, poolStatus);
    }

#ifdef LOSCFG_MEM_WATERLINE
    poolStatus->usageWaterLine = poolInfo->info.waterLine;
#endif
    MEM_UNLOCK(poolInfo, intSave);

    return 0;
}
